package mobi.zeedev.flyingsaucer.common.DataModule;

import android.app.Activity;
import android.app.ExpandableListActivity;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import mobi.zeedev.flyingsaucer.common.DataModule.FlyingSaucerConv.Stores;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

public class Util {

    private static final String TAG = "Util";

    public static final void expandAllGroups(ExpandableListActivity beerTree) {
        for (int i = 0; i < beerTree.getExpandableListAdapter().getGroupCount(); i++) {
            beerTree.getExpandableListView().expandGroup(i);
        }
    }

    //Uses SET NOT LIST
    public static final String[] asArReduce(Object... args) {
        Set<String> finalList = new HashSet<String>();
        if (args != null) {
            for (Object cur : args) {
                if (cur != null) {
                    if (cur.getClass().isArray()) {
                        String[] resAr = Util.asArReduce((Object[]) cur);
                        for (String cur2 : resAr) {
                            finalList.add(cur2);
                        }
                    } else {
                        finalList.add(cur.toString());
                    }
                }
            }
        }

        String[] arret = {};
        return finalList.toArray(arret);

    }

    //Uses LIST instead of SET
    //This does not reduce the argument list
    public static final String[] asArNonReduce(Object... args) {
        List<String> finalList = new ArrayList<String>();

        if (args != null) {
            for (Object cur : args) {
                if (cur != null) {
                    if (cur.getClass().isArray()) {
                        String[] resAr = Util.asArNonReduce((Object[]) cur);
                        //	  				finalList.add(resAr);
                        for (String cur2 : resAr) {
                            finalList.add(cur2);
                        }
                    } else {
                        finalList.add(cur.toString());
                    }
                }
            }
        }

        String[] arret = {};
        return finalList.toArray(arret);

    }

    public static final String[] asGlobal(String tableName, Object children) {
        List<String> retList = new ArrayList<String>();

        for (String cur : asArReduce(children)) {
            retList.add(mergeWithPeriod(tableName, cur));
        }


        return retList.toArray(new String[]{});
    }


    public static final String mergeWithPeriod(String tableName, String cur) {
        return tableName + "." + cur;
    }

    public static final Uri buildUriWithSecondPath(Uri uriIn, String storeDbId, String secondPath) {
        Uri withId = ContentUris.withAppendedId(uriIn, Long.valueOf(storeDbId));
        Uri withId2 = withId.buildUpon().appendPath(secondPath).build();
        return withId2;
    }


    public static final String[] asAr(Object... args) {
        String[] ar = new String[args.length];
        for (int i = 0; i < args.length; i++) {
//  			if (args[i].getClass().isArray()) {
////  				Object[] subAr = (Object[]) args[i];
////  				String[] subArStr = Functions.asAr(subAr);
//  				
//  			}
            if (args[i] != null) {
                ar[i] = args[i].toString();
            }
        }
        return ar;


    }

    public static final int[] asIntArray(Integer... args) {
        int[] ar = new int[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] != null) {
                ar[i] = args[i];
            }
        }
        return ar;
    }

    public static final Uri buildStoresBeersWithStoreId(String storeDbId) {
//		Uri withId = ContentUris.withAppendedId(StoresPreferencesModel.CONTENT_URI, Long.valueOf(storeDbId));
//		Uri withId2 = withId.buildUpon().appendPath("beers").build();
//		return withId;
        return buildUriWithSecondPath(Stores.CONTENT_URI, storeDbId, "beers");
    }


    public static final Boolean isTimeElapsed(Date lastQuery, Integer duration) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.MINUTE, -duration);
        int res = cal.getTime().compareTo(lastQuery);
        if (res > 0) {
            return true;
        } else {
            return false;
        }

    }

    public static final URL toURL(String urlStr) {
        URL url = null;
        try {
            url = new URL(urlStr);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return url;
    }

    public static final Boolean createMenu(Activity act, Menu menu, Integer xmlId) {
        MenuInflater inflater = act.getMenuInflater();
        inflater.inflate(xmlId, menu);
        return true;
    }

    public static final <A> Map<A, ContentValues> generateKeyMap(List<ContentValues> userBeerListIn, String key, Class<A> type) {
        Map<A, ContentValues> t = new HashMap<A, ContentValues>(userBeerListIn.size());

        for (ContentValues cv : userBeerListIn) {
            A keysValue = (A) cv.get(key);
            t.put(keysValue, cv);
        }
        return t;
    }

    public static final <A> A getFieldsValue(Object target, String fieldName, Class<A> class1) {
        Object columnName = null;
        A retValue = null;
        try {
            Field f = target.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            columnName = f.get(target);
            retValue = class1.cast(columnName);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return retValue;

    }

//	public static final <A> A getSuperField(Object target, String fieldName, Class<A> class1) {
//		Object columnName = null;
//		A retValue = null;
//		try {
//			Field f = target.getClass().getSuperclass().getDeclaredField(fieldName);
//			f.setAccessible(true);
//			columnName = f.get(target);
//			retValue = class1.cast(columnName);
//		} catch (Exception e1) {
//			e1.printStackTrace();
//		}
//		return retValue;
//		
//	}

    public static final <A> A getFromCursor(Cursor cursor, String columnName, Class<A> clazz) {
        String name = clazz.getSimpleName();
        String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
        A ret = null;
        try {
            Method m = cursor.getClass().getMethod(methodName, int.class);
            ret = (A) m.invoke(cursor, cursor.getColumnIndex(columnName));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;

    }

    public static final <A> A getReturnFunction(Object target, String methodName, Object[] args, Class<A> clazz) {
        Class[] params = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            params[i] = args[i].getClass();
        }

        Method m = null;
        A ret = null;
        try {
            m = target.getClass().getMethod(methodName, params);
            ret = (A) m.invoke(target, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static final <A> A getFindReturnFunction(Object target, String methodName, Object[] args, Class<A> clazz) {
//		Class[] params = null;
//		if (args != null) {
//			 params = new Class[args.length];
//			for (int i = 0; i < args.length; i++) {
//				params[i] = args[i].getClass().getSuperclass();
//			}
//		} else {
//			params = null;
//		}

        Method m = null;

        Method[] ms = target.getClass().getDeclaredMethods();
        for (Method mc : ms) {
            if (mc.getName().equals(methodName) && mc.getGenericParameterTypes().length == args.length) {
                m = mc;
                break;
            }
        }
        if (m == null) {
            Method[] ms2 = target.getClass().getSuperclass().getDeclaredMethods();
            for (Method mc : ms2) {
                if (mc.getName().equals(methodName) && mc.getGenericParameterTypes().length == args.length) {
                    m = mc;
                    break;
                }
            }
        }


        A ret = null;
        try {
//			if (m!=null) {
//				m = target.getClass().getDeclaredMethod(methodName, params);
            if (clazz != null) {
                ret = (A) m.invoke(target, args);
            } else {
                m.invoke(target, args);
            }
//			}
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static final <A> A getFindField(Object target, String fieldName, Class<A> clazz) {
//		Class[] params = null;
//		if (args != null) {
//			 params = new Class[args.length];
//			for (int i = 0; i < args.length; i++) {
//				params[i] = args[i].getClass().getSuperclass();
//			}
//		} else {
//			params = null;
//		}
        if (target == null) {
            return null;
        }
        Field m = null;
        Object currentTarget = target;
        while (!(currentTarget.getClass().getName().equals("Object"))) {


            Field[] ms = target.getClass().getDeclaredFields();
            for (Field mc : ms) {
                if (mc.getName().equals(fieldName)) {
                    m = mc;
                    break;
                }
            }
            currentTarget = currentTarget.getClass().getSuperclass();

        }
//		if (m == null) {
//			Field[] ms2 = target.getClass().getSuperclass().getDeclaredFields();
//			for (Field mc : ms2) {
//				if (mc.getName().equals(fieldName)) {
//					m = mc;
//					break;
//				}
//			}
//		}

//		if (m == null) {
//			Field[] ms2 = target.getClass().getSuperclass().getSuperclass().getDeclaredFields();
//			for (Field mc : ms2) {
//				if (mc.getName().equals(fieldName)) {
//					m = mc;
//					break;
//				}
//			}
//		}


        A ret = null;
        try {
            if (m != null) {
                m.setAccessible(true);
//				m = target.getClass().getDeclaredMethod(methodName, params);
                if (clazz != null) {
                    ret = (A) m.get(target);
                } else {
                    //m.invoke(target, args);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret;
    }

    public static final void setFieldValue(Object target, String fieldName, Object value) {
//		Object columnName = null;
//		A retValue = null;
        try {
            Field f = target.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
//			columnName = f.get(target);
//			retValue = class1.cast(columnName);
            f.set(target, value);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
//		return retValue;

    }

    public static final void setSuperFieldValue(Object target, String fieldName, Object value) {
//		Object columnName = null;
//		A retValue = null;
        try {

            Field[] fs = target.getClass().getDeclaredFields();
            for (Field c : fs) {
                Log.d(TAG, "Field: " + c.toString());
            }
            Class<?> targetClazz = target.getClass().getDeclaringClass();
            Log.d(TAG, "Dec. Clazz: " + targetClazz);
            Log.d(TAG, "Dec. Clazz: " + target.getClass().getSuperclass().getDeclaredField(fieldName));
//			for (Field c : fs2) {
//				Log.d(TAG, "Field: " + c.toGenericString());
//			}


            Field f = target.getClass().getSuperclass().getDeclaredField(fieldName);
            f.setAccessible(true);


//			columnName = f.get(target);
//			retValue = class1.cast(columnName);
            f.set(target, value);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
//		return retValue;

    }

    public static final Boolean intToBoolean(Integer num, Boolean defaultReturn) {
        Boolean ret = defaultReturn;
        if (num != null) {
            if (num == 1) {
                ret = true;
            } else if (num == 0) {
                ret = false;
            }
        }
        return ret;
    }

    public static final Object[] asObAr(Object... args) {
        Object[] newo = new Object[args.length];
        for (int i = 0; i < newo.length; i++) {
            newo[i] = args[i];
        }
        return args;
    }


}
